home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / basics / qtcreatemovie / qtsound.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  12.6 KB  |  462 lines

  1. /*
  2.     File:        QTSound.c
  3.     
  4.     Contains:    Sound code for QuickTime CreateMovie sample
  5.     
  6.     Written by:    Scott Kuechle
  7.                 (based heavily on QuickTime sample code in Inside Macintosh: QuickTime)
  8.  
  9.     Copyright:    © 1998 by Apple Computer, Inc. All rights reserved
  10.     
  11.     Change History (most recent first)
  12.     
  13.         <2>        9/28/98        rtm        changes for Metrowerks compiler
  14.         <1>        6/26/98        srk        first file
  15.  
  16.  
  17. */
  18.  
  19. /************************************************************
  20. *                                                           *
  21. *    INCLUDE FILES                                          *
  22. *                                                           *
  23. *************************************************************/
  24.  
  25.  
  26. #if !defined(_MSC_VER) && _WIN32
  27.     #include <Win32Headers.mch>
  28.     #define TARGET_OS_WIN32            1
  29. #else
  30.     #include <ConditionalMacros.h>
  31. #endif
  32.  
  33. #if TARGET_OS_WIN32
  34.     #include <QTML.h>
  35.     #define    STRICT
  36.     #include <windows.h>
  37. #endif
  38.  
  39. #include <Resources.h>
  40. #include <FixMath.h>
  41. #include <Sound.h>
  42.  
  43. #include "CreateMovie.h"
  44. #include "QTSound.h"
  45.  
  46. /************************************************************
  47. *                                                           *
  48. *    TYPE DEFINITIONS                                       *
  49. *                                                           *
  50. *************************************************************/
  51.  
  52. typedef SndCommand *SndCmdPtr;
  53.  
  54. #if PRAGMA_STRUCT_ALIGN
  55.     #pragma options align=mac68k
  56. #elif PRAGMA_STRUCT_PACKPUSH
  57.     #pragma pack(push, 2)
  58. #elif PRAGMA_STRUCT_PACK
  59.     #pragma pack(2)
  60. #endif
  61.  
  62.     /* 'snd ' resource format 1 - see the Sound Manager chapter of Inside Macintosh: Sound
  63.         for the details */
  64.     typedef struct 
  65.     {
  66.         short format;
  67.         short numSynths;
  68.     } Snd1Header, *Snd1HdrPtr, **Snd1HdrHndl;
  69.  
  70.     /* 'snd ' resource format 2 - see the Sound Manager chapter of Inside Macintosh: Sound
  71.         for the details */
  72.  
  73.     typedef struct 
  74.     {
  75.         short format;
  76.         short refCount;
  77.     } Snd2Header, *Snd2HdrPtr, **Snd2HdrHndl;
  78.  
  79.  
  80. #if PRAGMA_STRUCT_ALIGN
  81.     #pragma options align=reset
  82. #elif PRAGMA_STRUCT_PACKPUSH
  83.     #pragma pack(pop)
  84. #elif PRAGMA_STRUCT_PACK
  85.     #pragma pack()
  86. #endif
  87.  
  88. /************************************************************
  89. *                                                           *
  90. *    FUNCTION PROTOTYPES                                    *
  91. *                                                           *
  92. *************************************************************/
  93.  
  94. static void QTSound_CreateSoundDescription (Handle sndHandle,
  95.                                             SoundDescriptionHandle sndDesc,
  96.                                             long *sndDataOffset,
  97.                                             long *numSamples,
  98.                                             long *sndDataSize );
  99. static long QTSound_GetSndHdrOffset (Handle sndHandle);
  100.  
  101. /************************************************************
  102. *                                                           *
  103. *    CONSTANTS                                              *
  104. *                                                           *
  105. *************************************************************/
  106.  
  107. #define    kOurSoundResourceID 128
  108.  
  109. #define    kSoundSampleDuration 1
  110. #define    kSyncSample 0
  111. #define    kTrackStart    0
  112. #define    kMediaStart    0
  113. /* 
  114. for the following constants, please consult the Macintosh
  115. Audio Compression and Expansion Toolkit
  116. */
  117. #define kMACEBeginningNumberOfBytes 6
  118. #define kMACE31MonoPacketSize 2
  119. #define kMACE31StereoPacketSize 4
  120. #define kMACE61MonoPacketSize 1
  121. #define kMACE61StereoPacketSize 2
  122.  
  123.  
  124. /************************************************************
  125. *                                                           *
  126. *    QTSound_CreateMySoundTrack()                           *
  127. *                                                           *
  128. *    Creates a QuickTime movie sound track & media data     *
  129. *                                                           *
  130. *************************************************************/
  131.  
  132.  
  133. void QTSound_CreateMySoundTrack (Movie theMovie)
  134. {
  135.     Track theTrack;
  136.     Media theMedia;
  137.     Handle sndHandle = nil;
  138.     SoundDescriptionHandle sndDesc = nil;
  139.     long sndDataOffset;
  140.     long sndDataSize;
  141.     long numSamples;
  142.     OSErr err = noErr;
  143. #if TARGET_OS_WIN32
  144.  
  145.     char path[MAX_PATH+1];
  146.     short resID;
  147.     FSSpec fsspec;
  148.  
  149.  
  150.         fsspec.vRefNum = 0;
  151.         fsspec.parID = 0;
  152.         GetModuleFileName( NULL, path, MAX_PATH+1);
  153.  
  154.         NativePathNameToFSSpec((char *)&path, &fsspec, 0);
  155.  
  156.             /* open our application resource file so we
  157.                 can access the Macintosh 'snd ' resource */ 
  158.         resID = FSpOpenResFile(&fsspec, fsRdPerm);
  159.         CheckError (ResError(), "FSpOpenResFile error" );
  160.  
  161. #endif
  162.  
  163.  
  164.  
  165.         sndHandle = GetResource ('snd ', kOurSoundResourceID);
  166.         CheckError (ResError(), "GetResource error" );
  167.         if (sndHandle == nil)
  168.         {
  169.             return;
  170.         }
  171.  
  172.         sndDesc = (SoundDescriptionHandle) NewHandle(4);
  173.         CheckError (MemError(), "NewHandle error" );
  174.  
  175.         QTSound_CreateSoundDescription (sndHandle, 
  176.                                         sndDesc, 
  177.                                         &sndDataOffset, 
  178.                                         &numSamples, 
  179.                                         &sndDataSize );
  180.  
  181.         theTrack = NewMovieTrack (theMovie, 0, 0, kFullVolume);
  182.         CheckError (GetMoviesError(), "NewMovieTrack error" );
  183.  
  184.         theMedia = NewTrackMedia (theTrack, SoundMediaType,
  185.                                 FixRound ((**sndDesc).sampleRate),
  186.                                 nil, 0);
  187.         CheckError (GetMoviesError(), "NewTrackMedia error" );
  188.  
  189.         err = BeginMediaEdits (theMedia);
  190.         CheckError( err, "BeginMediaEdits error" );
  191.  
  192.         err = AddMediaSample(theMedia,
  193.                             sndHandle,
  194.                             sndDataOffset,/* offset in data */
  195.                             sndDataSize,
  196.                             kSoundSampleDuration,/* duration of each sound sample */
  197.                             (SampleDescriptionHandle) sndDesc,
  198.                             numSamples,
  199.                             kSyncSample,/* self-contained samples */
  200.                             nil);
  201.         CheckError( err, "AddMediaSample error" );
  202.  
  203.         err = EndMediaEdits (theMedia);
  204.         CheckError( err, "EndMediaEdits error" );
  205.  
  206.         err = InsertMediaIntoTrack (theTrack, 
  207.                                     kTrackStart,/* track start time */
  208.                                     kMediaStart,/* media start time */
  209.                                     GetMediaDuration (theMedia),
  210.                                     fixed1);
  211.         CheckError( err, "InsertMediaIntoTrack error" );
  212.  
  213.         if (sndDesc != nil)
  214.         {
  215.             DisposeHandle( (Handle)sndDesc);
  216.         }
  217.  
  218. /************************************************************
  219. *                                                           *
  220. *    QTSound_CreateSoundDescription()                       *
  221. *                                                           *
  222. *    Creates a SoundDescription structure for a given sound *
  223. *    sample                                                 *
  224. *                                                           *
  225. *************************************************************/
  226.  
  227. static void QTSound_CreateSoundDescription (Handle sndHandle,
  228.                                             SoundDescriptionHandle sndDesc,
  229.                                             long *sndDataOffset,
  230.                                             long *numSamples,
  231.                                             long *sndDataSize )
  232. {
  233.     long sndHdrOffset = 0;
  234.     long sampleDataOffset;
  235.     SoundHeaderPtr sndHdrPtr = nil;
  236.     long numFrames;
  237.     long samplesPerFrame;
  238.     long bytesPerFrame;
  239.     SoundDescriptionPtr sndDescPtr;
  240.  
  241.  
  242.         *sndDataOffset = 0;
  243.         *numSamples = 0;
  244.         *sndDataSize = 0;
  245.  
  246.         SetHandleSize( (Handle)sndDesc, sizeof(SoundDescription) );
  247.         CheckError(MemError(),"SetHandleSize error");
  248.         sndHdrOffset = QTSound_GetSndHdrOffset (sndHandle);
  249.         if (sndHdrOffset == 0)
  250.         {
  251.             CheckError(-1, "QTSound_GetSndHdrOffset error");
  252.         }
  253.  
  254.         /* we can use pointers since we don't move memory */
  255.         sndHdrPtr = (SoundHeaderPtr) (*sndHandle + sndHdrOffset);
  256.         sndDescPtr = *sndDesc;
  257.  
  258.         sndDescPtr->descSize = sizeof (SoundDescription);
  259.         /* total size of sound description structure */
  260.         sndDescPtr->resvd1 = 0;
  261.         sndDescPtr->resvd2 = 0;
  262.         sndDescPtr->dataRefIndex = 1;
  263.         sndDescPtr->compressionID = 0;
  264.         sndDescPtr->packetSize = 0;
  265.         sndDescPtr->version = 0;
  266.         sndDescPtr->revlevel = 0;
  267.         sndDescPtr->vendor = 0; 
  268.  
  269.         switch (sndHdrPtr->encode) 
  270.         {
  271.             case stdSH:
  272.                 sndDescPtr->dataFormat = kRawCodecType;
  273.                 /* uncompressed offset-binary data */
  274.                 sndDescPtr->numChannels = 1;
  275.                 /* number of channels of sound */
  276.                 sndDescPtr->sampleSize = 8;
  277.                 /* number of bits per sample */
  278.                 sndDescPtr->sampleRate = sndHdrPtr->sampleRate;
  279.                 /* sample rate */
  280.                 *numSamples = sndHdrPtr->length;
  281.                 *sndDataSize = *numSamples;
  282.                 bytesPerFrame = 1; 
  283.                 samplesPerFrame = 1;
  284.                 sampleDataOffset = (Ptr)&sndHdrPtr->sampleArea - (Ptr)sndHdrPtr;
  285.             break;
  286.  
  287.             case extSH:
  288.             {
  289.                 ExtSoundHeaderPtr extSndHdrP;
  290.  
  291.                     extSndHdrP = (ExtSoundHeaderPtr)sndHdrPtr;
  292.                     sndDescPtr->dataFormat = kRawCodecType;
  293.                     /* uncompressed offset-binary data */
  294.  
  295.                     /* we typecast a long to a short here, and it should really be fixed */
  296.                     sndDescPtr->numChannels = (short)extSndHdrP->numChannels;
  297.                     /* number of channels of sound */
  298.                     sndDescPtr->sampleSize = extSndHdrP->sampleSize;
  299.                     /* number of bits per sample */
  300.                     sndDescPtr->sampleRate = extSndHdrP->sampleRate; 
  301.                     /* sample rate */
  302.                     numFrames = extSndHdrP->numFrames;
  303.                     *numSamples = numFrames;
  304.                     bytesPerFrame = extSndHdrP->numChannels * ( extSndHdrP->sampleSize / 8);
  305.                     samplesPerFrame = 1;
  306.                     *sndDataSize = numFrames * bytesPerFrame;
  307.                     sampleDataOffset = (Ptr)(&extSndHdrP->sampleArea) - (Ptr)extSndHdrP;
  308.             }
  309.             break;
  310.  
  311.             case cmpSH:
  312.             {
  313.                 CmpSoundHeaderPtr cmpSndHdrP;
  314.  
  315.                 cmpSndHdrP = (CmpSoundHeaderPtr)sndHdrPtr;
  316.                 /* we typecast a long to a short here, and it should really be fixed */
  317.  
  318.                 sndDescPtr->numChannels = (short)cmpSndHdrP->numChannels;
  319.                 /* number of channels of sound */
  320.                 sndDescPtr->sampleSize = cmpSndHdrP->sampleSize;
  321.                 /* number of bits per sample before compression */
  322.                 sndDescPtr->sampleRate = cmpSndHdrP->sampleRate;
  323.                 /* sample rate */
  324.                 numFrames = cmpSndHdrP->numFrames; 
  325.                 sampleDataOffset =(Ptr)(&cmpSndHdrP->sampleArea) - (Ptr)cmpSndHdrP;
  326.                 
  327.                 switch (cmpSndHdrP->compressionID) 
  328.                 {
  329.                     case threeToOne:
  330.                         sndDescPtr->dataFormat = kMACE3Compression;
  331.                         /* compressed 3:1 data */
  332.                         samplesPerFrame = kMACEBeginningNumberOfBytes; 
  333.                         *numSamples = numFrames * samplesPerFrame;
  334.                         
  335.                         switch (cmpSndHdrP->numChannels) 
  336.                         {
  337.                             case 1:
  338.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  339.                                                     * kMACE31MonoPacketSize;
  340.                             break;
  341.                             
  342.                             case 2:
  343.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  344.                                                     * kMACE31StereoPacketSize;
  345.                             break;
  346.                             
  347.                             default: 
  348.                                 CheckError(-1, "Corrupt sound data" );
  349.                             break;
  350.                         }
  351.                         
  352.                     *sndDataSize = numFrames * bytesPerFrame;
  353.                     break;
  354.                     
  355.                     case sixToOne:
  356.                         sndDescPtr->dataFormat = kMACE6Compression; 
  357.                         /* compressed 6:1 data */
  358.                         samplesPerFrame = kMACEBeginningNumberOfBytes; 
  359.                         *numSamples = numFrames * samplesPerFrame;
  360.                         
  361.                         switch (cmpSndHdrP->numChannels) 
  362.                         {
  363.                             case 1:
  364.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  365.                                                     * kMACE61MonoPacketSize; 
  366.                             break;
  367.                             
  368.                             case 2:
  369.                                 bytesPerFrame = cmpSndHdrP->numChannels 
  370.                                                     * kMACE61StereoPacketSize; 
  371.                             break;
  372.                             
  373.                             default:
  374.                                 CheckError(-1, "Corrupt sound data" );
  375.                             break;
  376.                         }
  377.                         
  378.                         *sndDataSize = (*numSamples) * bytesPerFrame;
  379.                     break;
  380.                     
  381.                     default:
  382.                         CheckError(-1, "Corrupt sound data" );
  383.                     break;
  384.                     }
  385.                     
  386.                 } /* switch cmpSndHdrP->compressionID:*/
  387.                 
  388.                 break;  /* of cmpSH: */
  389.  
  390.                 default:
  391.                     CheckError(-1, "Corrupt sound data" );
  392.                 break;
  393.  
  394.         } /* switch sndHdrPtr->encode */
  395.         
  396.     *sndDataOffset = sndHdrOffset + sampleDataOffset; 
  397.  
  398.  
  399. /************************************************************
  400. *                                                           *
  401. *    QTSound_GetSndHdrOffset()                              *
  402. *                                                           *
  403. *    Returns an pointer to the first sound command in the   *
  404. *    sound resource                                         *
  405. *                                                           *
  406. *************************************************************/
  407.  
  408. static long QTSound_GetSndHdrOffset (Handle sndHandle)
  409. {
  410.     short howManyCmds;
  411.     long sndOffset = 0;
  412.     Ptr sndPtr;
  413.  
  414.         if (sndHandle == nil)
  415.         {
  416.             return 0;
  417.         }
  418.         sndPtr = *sndHandle;
  419.         if (sndPtr == nil)
  420.         {
  421.             return 0;
  422.         }
  423.  
  424.         if ((*(SndListPtr)sndPtr).format == firstSoundFormat) 
  425.         {
  426.             short synths = ((SndListPtr)sndPtr)->numModifiers;
  427.             sndPtr += ( sizeof(Snd1Header) + (sizeof(ModRef) * synths) );
  428.         }
  429.         else 
  430.         {
  431.             sndPtr += sizeof(Snd2Header);
  432.         }
  433.  
  434.         howManyCmds = *(short *)sndPtr;
  435.  
  436.         sndPtr += sizeof(howManyCmds);
  437.         /* 
  438.         sndPtr is now at the first sound command--cruise all
  439.         commands and find the first soundCmd or bufferCmd
  440.         */
  441.         while (howManyCmds > 0) 
  442.         {
  443.             switch (((SndCmdPtr)sndPtr)->cmd) 
  444.             {
  445.                 case (soundCmd + dataOffsetFlag):
  446.                 case (bufferCmd + dataOffsetFlag):
  447.                     sndOffset = ((SndCmdPtr)sndPtr)->param2;
  448.                     howManyCmds = 0;    /* done, get out of loop */
  449.                 break;
  450.                 
  451.                 default:/* catch any other type of commands */
  452.                     sndPtr += sizeof(SndCommand);
  453.                     howManyCmds--;
  454.                 break;
  455.             }
  456.         }/* done with all commands */
  457.  
  458.         return sndOffset;
  459. }/* of GetSndHdrOffset */ 
  460.